Data handling
The first thing to do is to load and regroup all these datasets into a single one.
- Load the
tidyverse library and, using read_csv(), load the 4 datasets in 4 separate tibbles called children, income, pop and religion.
library(tidyverse)
library(readxl)
children <- read_csv("Data/children_per_woman_total_fertility.csv")
income <- read_csv("Data/income_per_person_gdppercapita_ppp_inflation_adjusted.csv")
pop <- read_csv("Data/population_total.csv")
religion <- read_csv("Data/religion.csv")
- To reproduce the chart on the video, we need to determine the dominant religion in each country. In the
religion dataset, add a column Religion that will give the name of the dominant religion for each country. For this, you might want to use this method that returns the name of the column containing the maximum of each row of a table:
DF <- tibble(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4))
DF
## # A tibble: 3 × 3
## V1 V2 V3
## <dbl> <dbl> <dbl>
## 1 2 7 9
## 2 8 3 6
## 3 1 5 4
## [1] "V3" "V1" "V2"
DF <- religion %>% select(Buddhists:Unaffiliated)
religion <- religion %>%
mutate(Religion=names(DF)[max.col(DF)])
- Using
pivot_longer(), make all datasets tidy.
children should now contain 3 columns: Country, Year and Fertility.
income should now contain 3 columns: Country, Year and Income.
pop should now contain 3 columns: Country, Year and Population.
We will only consider data from 1800 to 2018. Example of syntax using the pipe operator %>%:
DF <- read_table("name 2010 2011 2012 2014
Kevin 10 11 12 123
Jane 122 56 23 4
"
)
DF
## # A tibble: 2 × 5
## name `2010` `2011` `2012`
## <chr> <dbl> <dbl> <dbl>
## 1 Kevin 10 11 12
## 2 Jane 122 56 23
## # … with 1 more variable:
## # 2014 <dbl>
DF %>%
select(name, '2010':'2012') %>%
pivot_longer(col=-name,
names_to="Year",
values_to="Score",
names_transform=list(Year = as.numeric))
## # A tibble: 6 × 3
## name Year Score
## <chr> <dbl> <dbl>
## 1 Kevin 2010 10
## 2 Kevin 2011 11
## 3 Kevin 2012 12
## 4 Jane 2010 122
## 5 Jane 2011 56
## 6 Jane 2012 23
The line names_transform=list(Year = as.numeric) is here to convert the character year values to numerical values.
children <- children %>%
pivot_longer(col=-Country,
names_to="Year",
values_to="Fertility",
names_transform=list(Year = as.numeric))
income <- income %>%
select(Country, '1800':'2018') %>%
pivot_longer(col=-Country,
names_to="Year",
values_to="Income",
names_transform=list(Year = as.numeric))
pop <- pop %>%
select(Country, '1800':'2018') %>%
pivot_longer(col=-Country,
names_to="Year",
values_to="Population",
names_transform=list(Year = as.numeric))
- Now we want to combine all these datasets into a single one called
dat, containing the columns Country, Year, Population, Religion, Fertility and Income. Look into the inner_join() function of the dplyr library (which is part of the tidyverse library). For the religion dataset, we will consider that the proportions of 2010 are representative of all times.
- So play with the
religion dataset so that it contains only two columns, Country and Religion, the data being filtered from the original religion dataset for the year 2010.
- Join the 4 datasets into one called
dat.
dat <- inner_join(children, income) %>%
inner_join(pop) %>%
inner_join(religion %>%
filter(Year==2010) %>%
select(Country, Religion) # that's the critical part
)
# write_csv(dat, "Data/dat.csv")
You should end up with a dataset like this one:
## # A tibble: 37,887 × 6
## Country Year Fertility Income
## <chr> <dbl> <dbl> <dbl>
## 1 Afghani… 1800 7 603
## 2 Afghani… 1801 7 603
## 3 Afghani… 1802 7 603
## 4 Afghani… 1803 7 603
## 5 Afghani… 1804 7 603
## 6 Afghani… 1805 7 603
## 7 Afghani… 1806 7 603
## 8 Afghani… 1807 7 603
## 9 Afghani… 1808 7 603
## 10 Afghani… 1809 7 603
## # … with 37,877 more rows, and 2
## # more variables:
## # Population <dbl>,
## # Religion <chr>
In case you struggled to get there, download the archive with the button at the top and get the dat tibble with dat <- read_csv("Data/dat.csv").
Now our dataset is ready, let’s plot it.
Plotting
- Load the library
ggplot2 and set the global theme to theme_bw() using theme_set()
library(ggplot2)
theme_set(theme_bw())
- Create a subset of
dat concerning your origin country. For me it will be dat_france
dat_france <- dat%>%filter(Country=="France")
- Plot the evolution of the income per capita and the number of children per woman as a function of the years, and make it look like that (notice the kinks during the two world wars):
ggplot(data=dat_france, aes(x=Year, y=Income))+
ggtitle("Household income in France")+
xlab("Year")+
ylab("Household income per capita per year [constant $]")+
annotate("rect", xmin=1914, xmax=1918, ymin=-Inf, ymax=Inf, alpha=.3)+
annotate("rect", xmin=1939, xmax=1945, ymin=-Inf, ymax=Inf, alpha=.3)+
geom_point(alpha=0.2, size=5)+
geom_smooth()

ggplot(data=dat_france, aes(x=Year, y=Fertility))+
ggtitle("Fertility in France")+
xlab("Year")+
lims(y=c(0,5))+
ylab("Children per woman")+
annotate("rect", xmin=1914, xmax=1918, ymin=-Inf, ymax=Inf, alpha=.3)+
annotate("rect", xmin=1939, xmax=1945, ymin=-Inf, ymax=Inf, alpha=.3)+
geom_line(size=2, color="red")

- Create a subset of
dat containing the data for your country plus all the neighbor countries (if you come from an island, the nearest countries…). For me, dat_france_region will contain data from France, Spain, Italy, Switzerland, Germany, Luxembourg and Belgium.
dat_france_region <- dat%>%
filter(Country %in% c("France", "Spain", "Italy", "Switzerland", "Germany", "Luxembourg", "Belgium"))
- Plot again income and fertility as a function of the years, but add a color corresponding to the country and a point size to its population:
ggplot(data=dat_france_region, aes(x=Year, y=Income, col=Country, size=Population))+
ggtitle("Household income in France and its region")+
xlab("Year")+
ylab("Household income per capita per year [constant $]")+
annotate("rect", xmin=1914, xmax=1918, ymin=-Inf, ymax=Inf, alpha=.3)+
annotate("rect", xmin=1939, xmax=1945, ymin=-Inf, ymax=Inf, alpha=.3)+
geom_point(alpha=0.5)

ggplot(data=dat_france_region, aes(x=Year, y=Fertility, col=Country, size=Population))+
ggtitle("Fertility in France and its region")+
xlab("Year")+
lims(y=c(0,5))+
ylab("Children per woman")+
annotate("rect", xmin=1914, xmax=1918, ymin=-Inf, ymax=Inf, alpha=.3)+
annotate("rect", xmin=1939, xmax=1945, ymin=-Inf, ymax=Inf, alpha=.3)+
geom_point(alpha=.5)

- Load the library
plotly and make the previous graphs interactive. You can make an interactive graph by calling ggplotly(), like that:
library(plotly)
P <- ggplot(data = dat_france, aes(x=Population, y=Income))+
geom_point()
ggplotly(P)# add dynamicTicks=TRUE allows redrawing ticks when zooming in
- Finally, you can add a slider to the interactive graph allowing selecting a value for another variable (just like in the video) by adding the keyword
frame = in the chart’s aesthetics. So now, make the graph of the video ! (you can also add the aesthetics id=Country to show the country name in the popup when hovering on a point).
library(plotly)
P <- ggplot(data=dat, aes(x=Income,
y=Fertility,
frame=Year,
col=Religion,
size=Population,
id=Country))+
geom_point(alpha=0.5)+
ggtitle("Fertility vs. Income in the World")+
xlab("Household income per capita per year [constant $]")+
lims(y=c(0,8))+
scale_x_log10()+
scale_size(range=c(1, 15))+
ylab("Children per woman")
ggplotly(P)
LS0tCnRpdGxlIDogIlIgRXhlcmNpc2VzIC0gUmVsaWdpb24gYW5kIGJhYmllcyIKZGF0ZSAgOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogCiAgICBodG1sX2RvY3VtZW50OgogICAgICAgIHRvYyAgICAgICAgICAgIDogdHJ1ZQogICAgICAgIHRvY19mbG9hdCAgICAgIDogdHJ1ZQogICAgICAgIHRvY19kZXB0aCAgICAgIDogNAogICAgICAgIGhpZ2hsaWdodCAgICAgIDogdGFuZ28KICAgICAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUKICAgICAgICBjb2RlX2Rvd25sb2FkICA6IHRydWUKcGFyYW1zOiAKICAgIHNvbHV0aW9uOgogICAgICAgIHZhbHVlOiB0cnVlCi0tLQoKYGBge3IgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIifQpsaWJyYXJ5KGRvd25sb2FkdGhpcykKZG93bmxvYWRfbGluaygKICBsaW5rID0gIi4vQXJjaGl2ZS56aXAiLAogIG91dHB1dF9uYW1lID0gIkRhdGEgRmlsZXMiLAogIGJ1dHRvbl9sYWJlbCA9ICJEb3dubG9hZCBEYXRhIEZpbGVzIiwKICBidXR0b25fdHlwZSA9ICJkZWZhdWx0IiwKICBoYXNfaWNvbiA9IFRSVUUsCiAgaWNvbiA9ICJmYSBmYS1zYXZlIiwKICBzZWxmX2NvbnRhaW5lZCA9IEZBTFNFCikKYGBgCjxicj4KCi0tLS0KCkluIHRoZXNlIGV4ZXJjaXNlcyB3ZSB3aWxsIHNlZSB0aGUgcG93ZXIgb2YgdGhlIGxpYnJhcmllcyBgZ2dwbG90MmAgYW5kIGBwbG90bHlgIHRvIG1ha2Ugc2Vuc2Ugb2Ygc3RhdGlzdGljYWwgZGF0YS4gVGhlIGdvYWwgaXMgdG8gcmVwcm9kdWNlIHRoZSBtb3ZpbmcgY2hhcnQgdGhhdCB5b3UgY2FuIHNlZSBpbiB0aGlzIHZpZGVvIGZyb20gSGFucyBSb3NsaW5nIC0tIEkgaW52aXRlIHlvdSB0byB3YXRjaCBoaXMgb3RoZXIgdmlkZW9zLCB0aGV5IGFyZSBxdWl0ZSBlbmxpZ2h0ZW5pbmcgYW5kIGluc3BpcmluZzoKCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlcjsiPgo8YSBocmVmPSJodHRwczovL3d3dy50ZWQuY29tL3RhbGtzL2hhbnNfcm9zbGluZ19yZWxpZ2lvbnNfYW5kX2JhYmllcz9sYW5ndWFnZT1lbiIgdGFyZ2V0PSJfYmxhbmsiPgo8aSBjbGFzcz0iZmFiIGZhLXlvdXR1YmUgZmEtNXgiPjwvaT4KPC9hPgo8L2Rpdj4KCjxicj4KPGJyPgoKRm9yIHRoaXMsIHdlIHdpbGwgbmVlZCB0byBnYXRoZXIgdGhlIGRhdGE6CgotIEZyb20gW0dhcG1pbmRlcl0oaHR0cHM6Ly93d3cuZ2FwbWluZGVyLm9yZy9kYXRhLyksIGRhdGEgcGVyIGNvdW50cnkgYW5kIHBlciB5ZWFyIGZyb20gMTgwMCB0byAyMDE4OgogICAgLSBbVGhlIGNoaWxkcmVuIHBlciB3b21hbiB0b3RhbCBmZXJ0aWxpdHldKERhdGEvY2hpbGRyZW5fcGVyX3dvbWFuX3RvdGFsX2ZlcnRpbGl0eS5jc3YpCiAgICAtIFtUaGUgaW5jb21lIHBlciBjYXBpdGFdKERhdGEvaW5jb21lX3Blcl9wZXJzb25fZ2RwcGVyY2FwaXRhX3BwcF9pbmZsYXRpb25fYWRqdXN0ZWQuY3N2KQogICAgLSBbVGhlIHRvdGFsIHBvcHVsYXRpb25dKERhdGEvcG9wdWxhdGlvbl90b3RhbC5jc3YpCi0gRnJvbSB0aGUgW1BFVyByZXNlYXJjaCBjZW50ZXJdKGh0dHBzOi8vd3d3LnBld2ZvcnVtLm9yZy8yMDE1LzA0LzAyL3JlbGlnaW91cy1wcm9qZWN0aW9uLXRhYmxlLzIwMTAvcGVyY2VudC9hbGwvKSwgZGF0YSBwZXIgY291bnRyeToKICAgICsgW1RoZSByZWxpZ2lvdXMgY29tcG9zaXRpb25dKERhdGEvcmVsaWdpb24uY3N2KQoKLS0tLS0tLSAKCiMgRGF0YSBoYW5kbGluZwoKVGhlIGZpcnN0IHRoaW5nIHRvIGRvIGlzIHRvIGxvYWQgYW5kIHJlZ3JvdXAgYWxsIHRoZXNlIGRhdGFzZXRzIGludG8gYSBzaW5nbGUgb25lLgoKMS4gTG9hZCB0aGUgYHRpZHl2ZXJzZWAgbGlicmFyeSBhbmQsIHVzaW5nIGByZWFkX2NzdigpYCwgbG9hZCB0aGUgNCBkYXRhc2V0cyBpbiA0IHNlcGFyYXRlIHRpYmJsZXMgY2FsbGVkIGBjaGlsZHJlbmAsIGBpbmNvbWVgLCBgcG9wYCBhbmQgYHJlbGlnaW9uYC4KCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPUZBTFNFfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShyZWFkeGwpCmNoaWxkcmVuIDwtIHJlYWRfY3N2KCJEYXRhL2NoaWxkcmVuX3Blcl93b21hbl90b3RhbF9mZXJ0aWxpdHkuY3N2IikKaW5jb21lICAgPC0gcmVhZF9jc3YoIkRhdGEvaW5jb21lX3Blcl9wZXJzb25fZ2RwcGVyY2FwaXRhX3BwcF9pbmZsYXRpb25fYWRqdXN0ZWQuY3N2IikKcG9wICAgICAgPC0gcmVhZF9jc3YoIkRhdGEvcG9wdWxhdGlvbl90b3RhbC5jc3YiKQpyZWxpZ2lvbiA8LSByZWFkX2NzdigiRGF0YS9yZWxpZ2lvbi5jc3YiKQpgYGAKCjIuIFRvIHJlcHJvZHVjZSB0aGUgY2hhcnQgb24gdGhlIHZpZGVvLCB3ZSBuZWVkIHRvIGRldGVybWluZSB0aGUgZG9taW5hbnQgcmVsaWdpb24gaW4gZWFjaCBjb3VudHJ5LiBJbiB0aGUgYHJlbGlnaW9uYCBkYXRhc2V0LCBhZGQgYSBjb2x1bW4gYFJlbGlnaW9uYCB0aGF0IHdpbGwgZ2l2ZSB0aGUgbmFtZSBvZiB0aGUgZG9taW5hbnQgcmVsaWdpb24gZm9yIGVhY2ggY291bnRyeS4gRm9yIHRoaXMsIHlvdSBtaWdodCB3YW50IHRvIHVzZSB0aGlzIG1ldGhvZCB0aGF0IHJldHVybnMgdGhlIG5hbWUgb2YgdGhlIGNvbHVtbiBjb250YWluaW5nIHRoZSBtYXhpbXVtIG9mIGVhY2ggcm93IG9mIGEgdGFibGU6CgpgYGB7ciBpbmNsdWRlPVRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgY2FjaGU9RkFMU0V9CkRGIDwtIHRpYmJsZShWMT1jKDIsOCwxKSxWMj1jKDcsMyw1KSxWMz1jKDksNiw0KSkKREYKbmFtZXMoREYpW21heC5jb2woREYpXQpgYGAKCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPUZBTFNFfQpERiA8LSByZWxpZ2lvbiAlPiUgc2VsZWN0KEJ1ZGRoaXN0czpVbmFmZmlsaWF0ZWQpCnJlbGlnaW9uIDwtIHJlbGlnaW9uICU+JSAKICAgICAgICBtdXRhdGUoUmVsaWdpb249bmFtZXMoREYpW21heC5jb2woREYpXSkKYGBgCgozLiBVc2luZyBgcGl2b3RfbG9uZ2VyKClgLCBtYWtlIGFsbCBkYXRhc2V0cyB0aWR5LiAKCi0gYGNoaWxkcmVuYCBzaG91bGQgbm93IGNvbnRhaW4gMyBjb2x1bW5zOiBgQ291bnRyeWAsIGBZZWFyYCBhbmQgYEZlcnRpbGl0eWAuIAotIGBpbmNvbWVgIHNob3VsZCBub3cgY29udGFpbiAzIGNvbHVtbnM6IGBDb3VudHJ5YCwgYFllYXJgIGFuZCBgSW5jb21lYC4gCi0gYHBvcGAgc2hvdWxkIG5vdyBjb250YWluIDMgY29sdW1uczogYENvdW50cnlgLCBgWWVhcmAgYW5kIGBQb3B1bGF0aW9uYC4gCgpXZSB3aWxsIG9ubHkgY29uc2lkZXIgZGF0YSBmcm9tIDE4MDAgdG8gMjAxOC4gRXhhbXBsZSBvZiBzeW50YXggdXNpbmcgdGhlIHBpcGUgb3BlcmF0b3IgYCU+JWA6CgpgYGB7cn0KREYgPC0gcmVhZF90YWJsZSgibmFtZSAgMjAxMCAgMjAxMSAgMjAxMiAgMjAxNApLZXZpbiAgMTAgICAgMTEgICAxMiAgIDEyMwpKYW5lICAgMTIyICAgNTYgICAyMyAgIDQKIgopCkRGCkRGICU+JSAKICAgIHNlbGVjdChuYW1lLCAnMjAxMCc6JzIwMTInKSAlPiUgCiAgICBwaXZvdF9sb25nZXIoY29sPS1uYW1lLAogICAgICAgICAgICAgICAgIG5hbWVzX3RvPSJZZWFyIiwgCiAgICAgICAgICAgICAgICAgdmFsdWVzX3RvPSJTY29yZSIsCiAgICAgICAgICAgICAgICAgbmFtZXNfdHJhbnNmb3JtPWxpc3QoWWVhciA9IGFzLm51bWVyaWMpKQpgYGAKVGhlIGxpbmUgYG5hbWVzX3RyYW5zZm9ybT1saXN0KFllYXIgPSBhcy5udW1lcmljKWAgaXMgaGVyZSB0byBjb252ZXJ0IHRoZSBjaGFyYWN0ZXIgeWVhciB2YWx1ZXMgdG8gbnVtZXJpY2FsIHZhbHVlcy4KCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPUZBTFNFfQpjaGlsZHJlbiA8LSBjaGlsZHJlbiAlPiUgCiAgICAgICAgICAgICAgICBwaXZvdF9sb25nZXIoY29sPS1Db3VudHJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190bz0iWWVhciIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlc190bz0iRmVydGlsaXR5IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190cmFuc2Zvcm09bGlzdChZZWFyID0gYXMubnVtZXJpYykpCmluY29tZSAgIDwtIGluY29tZSAlPiUgCiAgICAgICAgICAgICAgICBzZWxlY3QoQ291bnRyeSwgJzE4MDAnOicyMDE4JykgJT4lIAogICAgICAgICAgICAgICAgcGl2b3RfbG9uZ2VyKGNvbD0tQ291bnRyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdG89IlllYXIiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXNfdG89IkluY29tZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZXNfdHJhbnNmb3JtPWxpc3QoWWVhciA9IGFzLm51bWVyaWMpKQpwb3AgICAgICA8LSBwb3AgJT4lIAogICAgICAgICAgICAgICAgc2VsZWN0KENvdW50cnksICcxODAwJzonMjAxOCcpICU+JSAKICAgICAgICAgICAgICAgIHBpdm90X2xvbmdlcihjb2w9LUNvdW50cnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWVzX3RvPSJZZWFyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWVzX3RvPSJQb3B1bGF0aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lc190cmFuc2Zvcm09bGlzdChZZWFyID0gYXMubnVtZXJpYykpCmBgYAoKNC4gTm93IHdlIHdhbnQgdG8gY29tYmluZSBhbGwgdGhlc2UgZGF0YXNldHMgaW50byBhIHNpbmdsZSBvbmUgY2FsbGVkIGBkYXRgLCBjb250YWluaW5nIHRoZSBjb2x1bW5zIGBDb3VudHJ5YCwgYFllYXJgLCBgUG9wdWxhdGlvbmAsIGBSZWxpZ2lvbmAsIGBGZXJ0aWxpdHlgIGFuZCBgSW5jb21lYC4gTG9vayBpbnRvIHRoZSBgaW5uZXJfam9pbigpYCBmdW5jdGlvbiBvZiB0aGUgYGRwbHlyYCBsaWJyYXJ5ICh3aGljaCBpcyBwYXJ0IG9mIHRoZSBgdGlkeXZlcnNlYCBsaWJyYXJ5KS4gRm9yIHRoZSBgcmVsaWdpb25gIGRhdGFzZXQsIHdlIHdpbGwgY29uc2lkZXIgdGhhdCB0aGUgcHJvcG9ydGlvbnMgb2YgMjAxMCBhcmUgcmVwcmVzZW50YXRpdmUgb2YgYWxsIHRpbWVzLgoKLSBTbyBwbGF5IHdpdGggdGhlIGByZWxpZ2lvbmAgZGF0YXNldCBzbyB0aGF0IGl0IGNvbnRhaW5zIG9ubHkgdHdvIGNvbHVtbnMsIGBDb3VudHJ5YCBhbmQgYFJlbGlnaW9uYCwgdGhlIGRhdGEgYmVpbmcgZmlsdGVyZWQgZnJvbSB0aGUgb3JpZ2luYWwgYHJlbGlnaW9uYCBkYXRhc2V0IGZvciB0aGUgeWVhciAyMDEwLgotIEpvaW4gdGhlIDQgZGF0YXNldHMgaW50byBvbmUgY2FsbGVkIGBkYXRgLgoKYGBge3IgaW5jbHVkZT1wYXJhbXMkc29sdXRpb24sIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgY2FjaGU9RkFMU0V9CmRhdCA8LSBpbm5lcl9qb2luKGNoaWxkcmVuLCBpbmNvbWUpICU+JQogICAgICAgIGlubmVyX2pvaW4ocG9wKSAlPiUKICAgICAgICBpbm5lcl9qb2luKHJlbGlnaW9uICU+JSAKICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoWWVhcj09MjAxMCkgJT4lIAogICAgICAgICAgICAgICAgICAgIHNlbGVjdChDb3VudHJ5LCBSZWxpZ2lvbikgIyB0aGF0J3MgdGhlIGNyaXRpY2FsIHBhcnQKICAgICAgICAgICAgICAgICAgKQojIHdyaXRlX2NzdihkYXQsICJEYXRhL2RhdC5jc3YiKQpgYGAKCllvdSBzaG91bGQgZW5kIHVwIHdpdGggYSBkYXRhc2V0IGxpa2UgdGhpcyBvbmU6CgpgYGB7ciBlY2hvPUZBTFNFLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPUZBTFNFfQpkYXQKYGBgCgpJbiBjYXNlIHlvdSBzdHJ1Z2dsZWQgdG8gZ2V0IHRoZXJlLCBkb3dubG9hZCB0aGUgYXJjaGl2ZSB3aXRoIHRoZSBidXR0b24gYXQgdGhlIHRvcCBhbmQgZ2V0IHRoZSBgZGF0YCB0aWJibGUgd2l0aCBgZGF0IDwtIHJlYWRfY3N2KCJEYXRhL2RhdC5jc3YiKWB7LlJ9LgoKTm93IG91ciBkYXRhc2V0IGlzIHJlYWR5LCBsZXQncyBwbG90IGl0LgoKIyBQbG90dGluZwoKMS4gTG9hZCB0aGUgbGlicmFyeSBgZ2dwbG90MmAgYW5kIHNldCB0aGUgZ2xvYmFsIHRoZW1lIHRvIGB0aGVtZV9idygpYCB1c2luZyBgdGhlbWVfc2V0KClgCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjYWNoZT1GQUxTRX0KbGlicmFyeShnZ3Bsb3QyKQp0aGVtZV9zZXQodGhlbWVfYncoKSkKYGBgCgoyLiBDcmVhdGUgYSBzdWJzZXQgb2YgYGRhdGAgY29uY2VybmluZyB5b3VyIG9yaWdpbiBjb3VudHJ5LiBGb3IgbWUgaXQgd2lsbCBiZSBgZGF0X2ZyYW5jZWAKCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPUZBTFNFfQpkYXRfZnJhbmNlIDwtIGRhdCU+JWZpbHRlcihDb3VudHJ5PT0iRnJhbmNlIikKYGBgCgozLiBQbG90IHRoZSBldm9sdXRpb24gb2YgdGhlIGluY29tZSBwZXIgY2FwaXRhIGFuZCB0aGUgbnVtYmVyIG9mIGNoaWxkcmVuIHBlciB3b21hbiBhcyBhIGZ1bmN0aW9uIG9mIHRoZSB5ZWFycywgYW5kIG1ha2UgaXQgbG9vayBsaWtlIHRoYXQgKG5vdGljZSB0aGUga2lua3MgZHVyaW5nIHRoZSB0d28gd29ybGQgd2Fycyk6CgpgYGB7ciBlY2hvPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjYWNoZT1GQUxTRX0KZ2dwbG90KGRhdGE9ZGF0X2ZyYW5jZSwgYWVzKHg9WWVhciwgeT1JbmNvbWUpKSsKICAgIGdndGl0bGUoIkhvdXNlaG9sZCBpbmNvbWUgaW4gRnJhbmNlIikrCiAgICB4bGFiKCJZZWFyIikrCiAgICB5bGFiKCJIb3VzZWhvbGQgaW5jb21lIHBlciBjYXBpdGEgcGVyIHllYXIgW2NvbnN0YW50ICRdIikrCiAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MTkxNCwgeG1heD0xOTE4LCB5bWluPS1JbmYsIHltYXg9SW5mLCBhbHBoYT0uMykrCiAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MTkzOSwgeG1heD0xOTQ1LCB5bWluPS1JbmYsIHltYXg9SW5mLCBhbHBoYT0uMykrCiAgICBnZW9tX3BvaW50KGFscGhhPTAuMiwgc2l6ZT01KSsKICAgIGdlb21fc21vb3RoKCkKZ2dwbG90KGRhdGE9ZGF0X2ZyYW5jZSwgYWVzKHg9WWVhciwgeT1GZXJ0aWxpdHkpKSsKICAgIGdndGl0bGUoIkZlcnRpbGl0eSBpbiBGcmFuY2UiKSsKICAgIHhsYWIoIlllYXIiKSsKICAgIGxpbXMoeT1jKDAsNSkpKwogICAgeWxhYigiQ2hpbGRyZW4gcGVyIHdvbWFuIikrCiAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MTkxNCwgeG1heD0xOTE4LCB5bWluPS1JbmYsIHltYXg9SW5mLCBhbHBoYT0uMykrCiAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MTkzOSwgeG1heD0xOTQ1LCB5bWluPS1JbmYsIHltYXg9SW5mLCBhbHBoYT0uMykrCiAgICBnZW9tX2xpbmUoc2l6ZT0yLCBjb2xvcj0icmVkIikKYGBgCgo0LiBDcmVhdGUgYSBzdWJzZXQgb2YgYGRhdGAgY29udGFpbmluZyB0aGUgZGF0YSBmb3IgeW91ciBjb3VudHJ5IHBsdXMgYWxsIHRoZSBuZWlnaGJvciBjb3VudHJpZXMgKGlmIHlvdSBjb21lIGZyb20gYW4gaXNsYW5kLCB0aGUgbmVhcmVzdCBjb3VudHJpZXMuLi4pLiBGb3IgbWUsIGBkYXRfZnJhbmNlX3JlZ2lvbmAgd2lsbCBjb250YWluIGRhdGEgZnJvbSBGcmFuY2UsIFNwYWluLCBJdGFseSwgU3dpdHplcmxhbmQsIEdlcm1hbnksIEx1eGVtYm91cmcgYW5kIEJlbGdpdW0uCgpgYGB7ciBpbmNsdWRlPXBhcmFtcyRzb2x1dGlvbiwgd2FybmluZyA9IEZBTFNFLCBtZXNzYWdlPUZBTFNFLCBjYWNoZT1GQUxTRX0KZGF0X2ZyYW5jZV9yZWdpb24gPC0gZGF0JT4lCiAgICAgICAgZmlsdGVyKENvdW50cnkgJWluJSBjKCJGcmFuY2UiLCAiU3BhaW4iLCAiSXRhbHkiLCAiU3dpdHplcmxhbmQiLCAiR2VybWFueSIsICJMdXhlbWJvdXJnIiwgIkJlbGdpdW0iKSkKYGBgCgo1LiBQbG90IGFnYWluIGluY29tZSBhbmQgZmVydGlsaXR5IGFzIGEgZnVuY3Rpb24gb2YgdGhlIHllYXJzLCBidXQgYWRkIGEgY29sb3IgY29ycmVzcG9uZGluZyB0byB0aGUgY291bnRyeSBhbmQgYSBwb2ludCBzaXplIHRvIGl0cyBwb3B1bGF0aW9uOgoKYGBge3IgZWNobz1wYXJhbXMkc29sdXRpb24sIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgY2FjaGU9RkFMU0V9CmdncGxvdChkYXRhPWRhdF9mcmFuY2VfcmVnaW9uLCBhZXMoeD1ZZWFyLCB5PUluY29tZSwgY29sPUNvdW50cnksIHNpemU9UG9wdWxhdGlvbikpKwogICAgZ2d0aXRsZSgiSG91c2Vob2xkIGluY29tZSBpbiBGcmFuY2UgYW5kIGl0cyByZWdpb24iKSsKICAgIHhsYWIoIlllYXIiKSsKICAgIHlsYWIoIkhvdXNlaG9sZCBpbmNvbWUgcGVyIGNhcGl0YSBwZXIgeWVhciBbY29uc3RhbnQgJF0iKSsKICAgIGFubm90YXRlKCJyZWN0IiwgeG1pbj0xOTE0LCB4bWF4PTE5MTgsIHltaW49LUluZiwgeW1heD1JbmYsIGFscGhhPS4zKSsKICAgIGFubm90YXRlKCJyZWN0IiwgeG1pbj0xOTM5LCB4bWF4PTE5NDUsIHltaW49LUluZiwgeW1heD1JbmYsIGFscGhhPS4zKSsKICAgIGdlb21fcG9pbnQoYWxwaGE9MC41KQpnZ3Bsb3QoZGF0YT1kYXRfZnJhbmNlX3JlZ2lvbiwgYWVzKHg9WWVhciwgeT1GZXJ0aWxpdHksIGNvbD1Db3VudHJ5LCBzaXplPVBvcHVsYXRpb24pKSsKICAgIGdndGl0bGUoIkZlcnRpbGl0eSBpbiBGcmFuY2UgYW5kIGl0cyByZWdpb24iKSsKICAgIHhsYWIoIlllYXIiKSsKICAgIGxpbXMoeT1jKDAsNSkpKwogICAgeWxhYigiQ2hpbGRyZW4gcGVyIHdvbWFuIikrCiAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MTkxNCwgeG1heD0xOTE4LCB5bWluPS1JbmYsIHltYXg9SW5mLCBhbHBoYT0uMykrCiAgICBhbm5vdGF0ZSgicmVjdCIsIHhtaW49MTkzOSwgeG1heD0xOTQ1LCB5bWluPS1JbmYsIHltYXg9SW5mLCBhbHBoYT0uMykrCiAgICBnZW9tX3BvaW50KGFscGhhPS41KQpgYGAKCjYuIExvYWQgdGhlIGxpYnJhcnkgYHBsb3RseWAgYW5kIG1ha2UgdGhlIHByZXZpb3VzIGdyYXBocyBpbnRlcmFjdGl2ZS4gWW91IGNhbiBtYWtlIGFuIGludGVyYWN0aXZlIGdyYXBoIGJ5IGNhbGxpbmcgYGdncGxvdGx5KClgLCBsaWtlIHRoYXQ6CgpgYGB7ciBpbmNsdWRlPVRSVUUsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZT1GQUxTRSwgY2FjaGU9RkFMU0V9CmxpYnJhcnkocGxvdGx5KQpQIDwtIGdncGxvdChkYXRhID0gZGF0X2ZyYW5jZSwgYWVzKHg9UG9wdWxhdGlvbiwgeT1JbmNvbWUpKSsKICAgICAgICBnZW9tX3BvaW50KCkKZ2dwbG90bHkoUCkjIGFkZCBkeW5hbWljVGlja3M9VFJVRSBhbGxvd3MgcmVkcmF3aW5nIHRpY2tzIHdoZW4gem9vbWluZyBpbgpgYGAgCgo3LiBGaW5hbGx5LCB5b3UgY2FuIGFkZCBhIHNsaWRlciB0byB0aGUgaW50ZXJhY3RpdmUgZ3JhcGggYWxsb3dpbmcgc2VsZWN0aW5nIGEgdmFsdWUgZm9yIGFub3RoZXIgdmFyaWFibGUgKGp1c3QgbGlrZSBpbiB0aGUgdmlkZW8pIGJ5IGFkZGluZyB0aGUga2V5d29yZCBgZnJhbWUgPWAgaW4gdGhlIGNoYXJ0J3MgYWVzdGhldGljcy4gU28gbm93LCBtYWtlIHRoZSBncmFwaCBvZiB0aGUgdmlkZW8gISAoeW91IGNhbiBhbHNvIGFkZCB0aGUgYWVzdGhldGljcyBgaWQ9Q291bnRyeWAgdG8gc2hvdyB0aGUgY291bnRyeSBuYW1lIGluIHRoZSBwb3B1cCB3aGVuIGhvdmVyaW5nIG9uIGEgcG9pbnQpLgoKCmBgYHtyIGluY2x1ZGU9cGFyYW1zJHNvbHV0aW9uLCB3YXJuaW5nID0gRkFMU0UsIG1lc3NhZ2U9RkFMU0UsIGNhY2hlPUZBTFNFfQpsaWJyYXJ5KHBsb3RseSkKUCA8LSBnZ3Bsb3QoZGF0YT1kYXQsIGFlcyh4PUluY29tZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgeT1GZXJ0aWxpdHksIAogICAgICAgICAgICAgICAgICAgICAgICAgIGZyYW1lPVllYXIsIAogICAgICAgICAgICAgICAgICAgICAgICAgIGNvbD1SZWxpZ2lvbiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZT1Qb3B1bGF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgIGlkPUNvdW50cnkpKSsKICAgIGdlb21fcG9pbnQoYWxwaGE9MC41KSsKICAgIGdndGl0bGUoIkZlcnRpbGl0eSB2cy4gSW5jb21lIGluIHRoZSBXb3JsZCIpKwogICAgeGxhYigiSG91c2Vob2xkIGluY29tZSBwZXIgY2FwaXRhIHBlciB5ZWFyIFtjb25zdGFudCAkXSIpKwogICAgbGltcyh5PWMoMCw4KSkrCiAgICBzY2FsZV94X2xvZzEwKCkrCiAgICBzY2FsZV9zaXplKHJhbmdlPWMoMSwgMTUpKSsKICAgIHlsYWIoIkNoaWxkcmVuIHBlciB3b21hbiIpCmdncGxvdGx5KFApCmBgYAo=